/*
 * Originally written by Xinef - Copyright (C) 2016+ AzerothCore <www.azerothcore.org>, released under GNU AGPL v3 license: https://github.com/azerothcore/azerothcore-wotlk/blob/master/LICENSE-AGPL3
*/

#include "ScriptMgr.h"
#include "ScriptedCreature.h"
#include "ahnkahet.h"
#include "SpellAuras.h"
#include "SpellScript.h"

enum misc
{
    // ACTIONS
    ACTION_GUARDIAN_DIED            = 1,
};

enum spells
{
    // NADOX
    SPELL_BROOD_PLAGUE              = 56130,
    SPELL_BROOD_PLAGUE_H            = 59467,
    SPELL_BROOD_RAGE_H              = 59465,
    SPELL_ENRAGE                    = 26662, // Enraged if too far away from home
    //SPELL_SUMMON_SWARMERS         = 56119, //2x 30178  -- 2x every 10secs, spell works fine but i need specific coords
    //SPELL_SUMMON_SWARM_GUARD      = 56120, //1x 30176  -- at 50%hp, spell works fine but i need specific coords

    // ADDS
    SPELL_SPRINT                    = 56354,
    SPELL_GUARDIAN_AURA             = 56151,
    SPELL_SWARMER_AURA              = 56158,
};

enum creatures
{
    NPC_AHNKAHAR_SWARMER            = 30178,
    NPC_AHNKAHAR_GUARDIAN_ENTRY     = 30176,
};

enum events
{
    EVENT_CHECK_HEALTH              = 1,
    EVENT_CHECK_HOME                = 2,
    EVENT_PLAGUE                    = 3,
    EVENT_BROOD_RAGE                = 4,
    EVENT_SWARMER                   = 5,
    EVENT_SUMMON_GUARD              = 6,
};

enum sounds
{
    SOUND_AGGRO                     = 14033,
    SOUND_SUMMON1                   = 14034,
    SOUND_SUMMON2                   = 14035,
    SOUND_SLAY1                     = 14036,
    SOUND_SLAY2                     = 14037,
    SOUND_SLAY3                     = 14038,
    SOUND_DEATH                     = 14039,
};

#define EMOTE_HATCHES        "An Ahn'kahar Guardian hatches!"

class boss_elder_nadox : public CreatureScript
{
public:
    boss_elder_nadox() : CreatureScript("boss_elder_nadox") { }

    struct boss_elder_nadoxAI : public ScriptedAI
    {
        boss_elder_nadoxAI(Creature *c) : ScriptedAI(c), summons(me)
        {
            pInstance = c->GetInstanceScript();
        }

        EventMap events;
        InstanceScript *pInstance;
        SummonList summons;

        void SummonHelpers(bool swarm)
        {
            Creature *cr;
            if (swarm)
            {
                if ((cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 640.425f, -919.544f, 25.8701f, 2.56563f)))
                    summons.Summon(cr);
                if ((cr = me->SummonCreature(NPC_AHNKAHAR_SWARMER, 655.891f, -930.445f, 25.6978f, 3.64774f)))
                    summons.Summon(cr);
            }
            else
            {
                if ((cr = me->SummonCreature(NPC_AHNKAHAR_GUARDIAN_ENTRY, 658.677f, -934.332f, 25.6978f, 3.03687f)))
                    summons.Summon(cr);
            }
        }

        void Reset()
        {
            events.Reset();
            summons.DespawnAll();

            if (pInstance)
            {
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, NOT_STARTED);
                pInstance->SetData(DATA_NADOX_ACHIEVEMENT, true);
            }
        }

        void EnterCombat(Unit * /*who*/)
        {
            me->MonsterYell("The secrets of the deep shall remain hidden.", LANG_UNIVERSAL, 0);
            me->PlayDirectSound(SOUND_AGGRO);

            events.ScheduleEvent(EVENT_CHECK_HEALTH, 1000);
            events.ScheduleEvent(EVENT_SWARMER, 10000);
            events.ScheduleEvent(EVENT_CHECK_HOME, 2000);
            events.ScheduleEvent(EVENT_PLAGUE, 5000+rand()%3000);
            events.ScheduleEvent(EVENT_BROOD_RAGE, 5000);

            if (pInstance)
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, IN_PROGRESS);
        }

        void DoAction(int32 param)
        {
            if (param == ACTION_GUARDIAN_DIED)
            {
                if (pInstance)
                    pInstance->SetData(DATA_NADOX_ACHIEVEMENT, false);
            }
        }

        void KilledUnit(Unit * /*victim*/)
        {
            if (urand(0,1))
                return;

            switch (rand()%3)
            {
                case 0: 
                    me->MonsterYell("Sleep now, in the cold dark.", LANG_UNIVERSAL,0);
                    me->PlayDirectSound(SOUND_SLAY1);
                    break;
                case 1: 
                    me->MonsterYell("For the Lich King!", LANG_UNIVERSAL,0);
                    me->PlayDirectSound(SOUND_SLAY2);
                    break;
                case 2: 
                    me->MonsterYell("Perhaps we will be allies soon.", LANG_UNIVERSAL,0);
                    me->PlayDirectSound(SOUND_SLAY3);
                    break;
            }
        }

        void JustDied(Unit* /*killer*/)
        {
            events.Reset();
            summons.DespawnAll();
            
            me->MonsterYell("Master, is my service complete?", LANG_UNIVERSAL, 0);
             me->PlayDirectSound(SOUND_DEATH);
            if (pInstance)
                pInstance->SetData(DATA_ELDER_NADOX_EVENT, DONE);
        }

        void JustSummoned(Creature* cr)
        {
            if (cr)
            {
                if (cr->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY )
                {
                    switch (rand()%2)
                    {
                        case 0: 
                            me->MonsterYell("The young must not grow hungry...", LANG_UNIVERSAL, 0);
                            me->PlayDirectSound(SOUND_SUMMON1);
                            break;
                        case 1: 
                            me->MonsterYell("Shhhad ak kereeesshh chak-k-k!", LANG_UNIVERSAL, 0);
                            me->PlayDirectSound(SOUND_SUMMON2);
                            break;
                    }
                }
                
                summons.Summon(cr);
            }
        }
        void UpdateAI(uint32 diff)
        {
            if (!UpdateVictim())
                return;

            events.Update(diff);

            if( me->HasUnitState(UNIT_STATE_CASTING) )
                return;

            switch ( events.GetEvent() )
            {
                case EVENT_CHECK_HEALTH:
                {
                    events.RepeatEvent(1000);
                    if (HealthBelowPct(50))
                    {
                        events.CancelEvent(EVENT_CHECK_HEALTH);
                        events.ScheduleEvent(EVENT_SUMMON_GUARD, 100);
                    }
                    break;
                }
                case EVENT_SUMMON_GUARD:
                {
                    me->MonsterTextEmote(EMOTE_HATCHES, me, true);
                    SummonHelpers(false);
                    events.PopEvent();
                    break;
                }
                case EVENT_BROOD_RAGE:
                {
                    if (Creature *pSwarmer = me->FindNearestCreature(NPC_AHNKAHAR_SWARMER, 40, true))
                        me->CastSpell(pSwarmer, SPELL_BROOD_RAGE_H, true);
                    
                    events.RepeatEvent(10000);
                    break;
                }
                case EVENT_PLAGUE:
                {
                    me->CastSpell(me->GetVictim(), DUNGEON_MODE(SPELL_BROOD_PLAGUE, SPELL_BROOD_PLAGUE_H), false);
                    events.RepeatEvent(12000+rand()%5000);
                    break;
                }
                case EVENT_SWARMER:
                {
                    SummonHelpers(true);
                    events.RepeatEvent(10000);
                    break;
                }
                case EVENT_CHECK_HOME:
                {
                    if (me->HasAura(SPELL_ENRAGE))
                        break;

                    if (me->GetPositionZ() < 24)
                    {
                        me->CastSpell(me, SPELL_ENRAGE, true);
                        events.PopEvent();
                        break;
                    }

                    events.RepeatEvent(2000);
                    break;
                }
            }

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new boss_elder_nadoxAI(creature);
    }
};

class npc_ahnkahar_nerubian : public CreatureScript
{
public:
    npc_ahnkahar_nerubian() : CreatureScript("npc_ahnkahar_nerubian") { }

    struct npc_ahnkahar_nerubianAI : public ScriptedAI
    {
        npc_ahnkahar_nerubianAI(Creature *c) : ScriptedAI(c) { }

        
        uint32 uiSprintTimer;
        void Reset()
        {
            if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
                me->CastSpell(me, SPELL_GUARDIAN_AURA, true);
            else // Swarmers
                me->CastSpell(me, SPELL_SWARMER_AURA, true);
            
            if (me->GetEntry() == NPC_AHNKAHAR_SWARMER || me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
                me->SetInCombatWithZone();

            uiSprintTimer = 10000;
        }

        void JustDied(Unit * /*killer*/)
        {
            if (me->GetEntry() == NPC_AHNKAHAR_GUARDIAN_ENTRY)
            {
                if (InstanceScript *pInstance = me->GetInstanceScript()) 
                    if (Creature *nadox = ObjectAccessor::GetCreature(*me, pInstance->GetData64(DATA_ELDER_NADOX)))
                        nadox->AI()->DoAction(ACTION_GUARDIAN_DIED);

                me->RemoveAllAuras();
            }
        }

        void UpdateAI(uint32 diff)
        {
            if (!UpdateVictim())
                return;

            if (uiSprintTimer <= diff)
            {
                me->CastSpell(me, SPELL_SPRINT, false);
                uiSprintTimer = 15000;
            }
            else 
                uiSprintTimer -= diff;

            DoMeleeAttackIfReady();
        }
    };

    CreatureAI *GetAI(Creature *creature) const
    {
        return new npc_ahnkahar_nerubianAI(creature);
    }
};

class spell_ahn_kahet_swarmer_aura : public SpellScriptLoader
{
    public:
        spell_ahn_kahet_swarmer_aura() : SpellScriptLoader("spell_ahn_kahet_swarmer_aura") { }

        class spell_ahn_kahet_swarmer_aura_SpellScript : public SpellScript
        {
            PrepareSpellScript(spell_ahn_kahet_swarmer_aura_SpellScript)

            void HandleDummy(SpellEffIndex /*effIndex*/)
            {
                Unit* caster = GetCaster();
                std::list<Creature*> swarm, swarm2;
                caster->GetCreaturesWithEntryInRange(swarm, 40.0f, 30338);
                caster->GetCreaturesWithEntryInRange(swarm2, 40.0f, 30178);
                int32 aliveCount = -1; // minus self

                std::list<Creature*>::const_iterator itr;
                for (itr = swarm.begin(); itr != swarm.end(); ++itr)
                    if ((*itr)->IsAlive())
                        aliveCount++;
                for (itr = swarm2.begin(); itr != swarm2.end(); ++itr)
                    if ((*itr)->IsAlive())
                        aliveCount++;

                if (Aura *aur = caster->GetAura(56281))
                {
                    if (aliveCount > 0)
                        aur->SetStackAmount(aliveCount);
                    else
                        aur->Remove();
                }
                else if (aliveCount > 0)
                {
                    caster->CastCustomSpell(caster, 56281, &aliveCount, &aliveCount, &aliveCount, true);
                    if (Aura *aur = caster->GetAura(56281))
                        aur->SetStackAmount(aliveCount);
                }
            }

            void Register()
            {
                OnEffectHitTarget += SpellEffectFn(spell_ahn_kahet_swarmer_aura_SpellScript::HandleDummy, EFFECT_0, SPELL_EFFECT_DUMMY);
            }
        };

        SpellScript* GetSpellScript() const
        {
            return new spell_ahn_kahet_swarmer_aura_SpellScript();
        }
};

void AddSC_boss_elder_nadox()
{
    new boss_elder_nadox();
    new npc_ahnkahar_nerubian();
    new spell_ahn_kahet_swarmer_aura();
}
